package com.mytx.notify.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mytx.common.exception.DecodeException;
import com.mytx.common.exception.RequestExpireException;
import com.mytx.common.utils.HttpEncryptUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.StreamUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.Enumeration;
import java.util.NoSuchElementException;

@SuppressWarnings("Duplicates")
public class DecodeFilter extends OncePerRequestFilter {
    private static final String servicePrivatekey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHXLqEITtVT9SsEc7oGZl5VZWsbDliXNUQW9tx8p9Ky3U/S3DkQrqnu6VxY9LL/n20LUxt2LKJn37fydGifYpXIi5Gcpdvuu0inZzlGuIRkdogDyqaPvl3g9im2yxZXQswtyz58vHTRvhcMjpD2Vr/X74WH+c/iv1DAjK7ZC9cIB3dJpDHGvVB0vlkcPNWaFXsHbh09CIr1NvvEiqsUysXusCvgF7zwpvdyRqUphQfWGfftkVUb6+N3/sJMG6656g2OknsqVeUGJvjpeneMGW99tp4pQ31EWX55skvmRY8fcu1QPxCMp0Ia4KgfbRG8IosjhPUCqBapNmEn+vMJJ6FAgMBAAECggEAYrixWy41bLnlPH1cbpBFC2Xs3CyuCVv1FJI50LgHjvAmGbx2oDM+mJhVSAZqtdZsbVzgMfjp9U86pBI37w8qNvQ51a07XwRwcF+NDtZ1bCT4dYs6Ifat0Il7F+4fQSmHwMbHaZ/S2KkY93y2W8eJA1kbdF1eNUyz+wv+XgbqN4Auqo7Dz2IpLkvYUuTPGnE3OuhrKK7qADKEEehuad5YZu1sr4nS2sdf9AE/Oin6TRHF50oAwwa82F886BmuVgj5H2hHkh5WM8XIj/KVbo2xvHVf+1aUhSOVmkPgq1R55o/AxGHtXH5lwuLEwiEEDKWej3WxMOkQAvLKvmDr5Yp9PQKBgQDWXK9g50fOPuv9ilvWSPVZ6D2+A9lFDt+3FDau/j0GSpSJJZmoyhLgVK7EDsaFIovNZ/+tI2vxpjwr7AqqLRt+IMrRR/Zzj6psOaVMH/KOsgR9Da3UiRoHgcwLenHEoc2U3UX1bRb9pmmpH5ujgHCAadvmIa2yr1CnLp/G6cFOywKBgQChp7efdcmE8TCdU1SekdITixawduOWF5furUZ2OzvrBl+hO99cbkjgrsEfQfgQpniYTFHPh4LXC5Vcyd6ZuT5dJUl4fcLjJig5ekkAEqrSce9PRNP+TyqmCr+tz1lTjFuKKn8bTP9frr60G8eD1EAwNfHaMZZzvB73E4+1s8tN7wKBgHzYZEgiyz5ChT0YDN6jhUnEqdj18t92hzLgcey/I5l7bEDoBjM45X+Dsnl7RYGamiOac11KKP8HWzoVciykssNlo9n5eH7baF05wZyxappS8axHgDstUlyW6tiwinwD5HDT4n/K9j3qYtVeFE5Iar1PagQBD2HnGykTTXkTAUO7AoGAaTV7t4d0YVaMGkhqsU0cWWXTnYOy+TNfyZHyYu6IP50FTi1mYITSX5C81fgcV9HQeOZq9FMwn37Fdf9YJdo/MWYcHBRVa3qhAU+KBUcg8BgA9SlJg6DIlAo42Ak0DMEzroeb9Au3xPE44oWV40GXiQkC38wYLDjKOmn7xPlAHvcCgYEAmOX9PWA7RdgzcTKyH2kHOu/pgMwT8QarpRaO1F9HpjnC3cdcCkPPE4F/R6VKy4Zfca1yiOzK+bxxBlJxmLQQywuaFRmWXNytiqbU7zwBXI6SJeo5EvrU8PSif4ctOpQzyhxYFTDgtyauqrW0ws4ZCqlt+9zGBaiIqTDLxUWexO8=";
    public static final String AUTHORIZATION = "Authorization";
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        //如果是get请求，直接放行
        if (StringUtils.equals(request.getMethod(), "GET")) {
            filterChain.doFilter(request, response);
            return;
        }
        //默认是加密请求，如果header中没有Encrypt，说明这个请求是加密的。有的 Encrypt,反而是不加密的，也许这样有点反人类，以后再考虑是否修改，，，
        String encrypt = request.getHeader("Encrypt");
        if (StringUtils.isNotEmpty(encrypt)) {
            filterChain.doFilter(request, response);
            return;
        }

        ServletInputStream inputStream = request.getInputStream();
        String content = StreamUtils.copyToString(inputStream, Charset.forName("UTF-8"));

        if (StringUtils.isEmpty(content)) {
            logger.info("body为空，跳过解密步骤：" + request.getRequestURL());
            filterChain.doFilter(request, response);
            return;
        }
        // logger.info("原始的body：" + content);
        JSONObject decrypt;
        try {
            //对加密请求body进行解密
            decrypt = HttpEncryptUtil.serverDecrypt(content, servicePrivatekey);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("解密错误" + content);
            throw new DecodeException("解密错误");
        }
        // logger.info("解密后的body：" + decrypt.toString());
        Date created = decrypt.getDate("created");
        //如果客户端的请求创建时间在5秒钟之前，我们认为此请求已经过期，
        if (created.before(new Date(System.currentTimeMillis() - 7200 * 1000))) {
            logger.error("请求过期" + decrypt);
            throw new RequestExpireException("请求过期");
        }
        //生成request的包装类，因为原生的HttpServletRequest，不支持对body的修改，等于说body,只能读取一次
        MyHttpServletRequestWrapper wrapper = new MyHttpServletRequestWrapper(request);
        //如果含有token,把它放入 request包装类的header里面，方便下一个过滤器：Authfilter里面调用
        if (decrypt.containsKey("token")) {
            wrapper.setToken(decrypt.getString("token"));

        }
        //把ak放入包装类
        wrapper.setAesKey(decrypt.getString("ak"));

        //这儿需要做判断，有可能 body里面只有token,比如autoLoin的请求，就不含有content，
        if (decrypt.containsKey("ct")) {
            //把解密后端额body，放入包装类
            wrapper.setRequestBody(decrypt.getString("ct"));
        }
        filterChain.doFilter(wrapper, response);

    }

    private class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
        private static final String AES_KEY = "AK";

        private String aesKey = "";
        private String token = "";
        private byte[] requestBody = null;


        public MyHttpServletRequestWrapper(HttpServletRequest request) {

            super(request);

            try {
                requestBody = StreamUtils.copyToByteArray(request.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


        @Override
        public ServletInputStream getInputStream() throws IOException {
            if (requestBody == null) {
                requestBody = new byte[0];
            }
            final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
            return new ServletInputStream() {
                @Override
                public int read() throws IOException {
                    return bais.read();
                }

                @Override
                public boolean isFinished() {
                    return false;
                }

                @Override
                public boolean isReady() {
                    return true;
                }

                @Override
                public void setReadListener(ReadListener listener) {

                }
            };
        }

        @Override
        public String getHeader(String name) {
            if (StringUtils.equals(name, AES_KEY)) {
                return this.aesKey;
            } else if (StringUtils.equals(name, AUTHORIZATION)) {
                return this.token;
            }

            return super.getHeader(name);
        }


        @Override
        public Enumeration<String> getHeaders(String name) {

            if (null != name && name.equals(AES_KEY)) {
                return new Enumeration<String>() {
                    private boolean hasGetted = false;

                    @Override
                    public String nextElement() {
                        if (hasGetted) {
                            throw new NoSuchElementException();
                        } else {
                            hasGetted = true;
                            return aesKey;
                        }
                    }

                    @Override
                    public boolean hasMoreElements() {
                        return !hasGetted;
                    }
                };
            }
            return super.getHeaders(name);

        }

        @Override
        public Enumeration<String> getHeaderNames() {
            return super.getHeaderNames();
        }

        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }

        public void setRequestBody(String bodyStr) throws UnsupportedEncodingException {
            this.requestBody = bodyStr.getBytes();
        }

        // 传入是JSON格式 转换成JSONObject
        public JSONObject getRequestBody() throws UnsupportedEncodingException {
            return JSON.parseObject((new String(requestBody, "UTF-8")));
        }

        public void setRequestBody(JSONObject jsonObject) throws UnsupportedEncodingException {
            this.requestBody = jsonObject.toJSONString().getBytes();
        }

        public void setAesKey(String aesKey) {
            this.aesKey = aesKey;
        }

        public void setToken(String token) {
            this.token = token;
        }
    }

}
